#include "stdafx.h"
#include "general.h"
#include "OffsetsCalc.h"

int GetDataPos(char* data, int dataLen, char* message, int messageLen)
{
	int dataPos = 0;
	for (int i = 0; i < dataLen; i++)
	{
		if (data[i] == message[dataPos])
		{
			dataPos++;
			if (dataPos == messageLen)
				return i - (dataPos - 1); // found. return position;

			if (i + 1 == dataLen && dataPos + 1 < messageLen)
				return -2;
		}
		else
		{
			dataPos = 0;
		}
	}

	return -1;
}

int FindDataPos(FILE* f, int startFrom, char* searchData, int searchDataLen)
{
	
	int dataLen = 1024;
	char* data = new char[dataLen];
	int bytesReaded = 0;
	int filePos = startFrom;

	fseek(f, startFrom, SEEK_SET);

	do
	{
		bytesReaded = fread(data, 1, dataLen, f);
		int result = GetDataPos(data, dataLen, searchData, searchDataLen); 
		if (result >= 0)
			return filePos + result;

		if (result == -2)
		{
			char *moreData = new char[dataLen * 2];
			memcpy(moreData, data, dataLen);
			bytesReaded+= fread(moreData + dataLen, 1, dataLen, f);
			
			result = GetDataPos(moreData, dataLen * 2, searchData, searchDataLen);
			delete [] moreData;
			if (result >= 0)
				return filePos + result;
		}
		
		filePos += bytesReaded;
	}
	while (bytesReaded > 0);

	delete [] data;
	
	return -1;
}

IMAGE_SECTION_HEADER* GetSectionByName(IMAGE_SECTION_HEADER* allSections, int sectionsCount, char* sectionName)
{
	for (int i = 0; i < sectionsCount; i++)
	{
		if (strcmp((char*)allSections[i].Name, sectionName) == 0)
		{
			return allSections + i;
		}
	}
}

DWORD inline GetBranchAddr(DWORD pc, DWORD instruction)
{
	return (pc +  (((instruction & 0x00FFFFFF) << 2) + 8)) & 0x00FFFFFF;
}


int GenCode(TCHAR* fileName, MANILA_TODAY_PATCH_SETTINGS* settings)
{
	FILE* f = _wfopen(fileName, L"rb");
	if (!f)
		return ERROR_FILE_NOT_FOUND;
	
	IMAGE_DOS_HEADER dosHeader;
	fread(&dosHeader, sizeof(IMAGE_DOS_HEADER), 1, f);
	if (dosHeader.e_magic != IMAGE_DOS_SIGNATURE)
		return ERROR_INVALID_FILE;

	IMAGE_NT_HEADERS32 ntHeader;
	fseek(f, dosHeader.e_lfanew, SEEK_SET);
	fread(&ntHeader, sizeof(ntHeader), 1, f);
	

	IMAGE_SECTION_HEADER* sectionHeaders = new IMAGE_SECTION_HEADER[ntHeader.FileHeader.NumberOfSections];
	for (int i = 0; i < ntHeader.FileHeader.NumberOfSections; i++)
	{
		fread(sectionHeaders + i, sizeof(IMAGE_SECTION_HEADER), 1, f);
	}

	IMAGE_SECTION_HEADER* rdataSection = GetSectionByName(sectionHeaders, ntHeader.FileHeader.NumberOfSections, ".rdata");
	TCHAR *message = L"Navigate in complete: ";
	int navPos = FindDataPos(f, rdataSection->PointerToRawData, ((char*)message), wcslen(message) * sizeof(TCHAR));
	DWORD virtualAddress = rdataSection->VirtualAddress + navPos - rdataSection->PointerToRawData 
		+ ntHeader.OptionalHeader.ImageBase;
	
	IMAGE_SECTION_HEADER* rtextSection = GetSectionByName(sectionHeaders, ntHeader.FileHeader.NumberOfSections, ".text");
	
	int searchesCnt = 0; 
	int searchStartPos = rtextSection->PointerToRawData;
	int callPos = -1;
	int callFnDataSize = 0x1000;
	char* callFnAddrCode = new char[callFnDataSize];
	int addrPos;

	do
	{
		addrPos = FindDataPos(f, searchStartPos, (char*)&virtualAddress, sizeof(DWORD));

		fseek(f, addrPos - callFnDataSize, SEEK_SET);
		fread(callFnAddrCode, 1, callFnDataSize, f);
		
		
		for (int i = 2; i < callFnDataSize - 1; i++)
		{
			if (callFnAddrCode[i] == (char)0x9F && callFnAddrCode[i + 1] == (char)0xE5 && (((callFnAddrCode[i - 1] >> 4) & (char)0xF) == 1))
			{
				int callAddr = callFnDataSize - i - 8 + 2;
				if (callAddr == (((callFnAddrCode[i - 1] & 0xF) << 8) | (callFnAddrCode[i - 2] & 0x000000FF) ))
				{
					callPos = i - 2; // that is it!!
					break; ;
				}
			}
		}
		searchStartPos = addrPos + 1;
		searchesCnt++;
	}
	while(callPos == -1 && searchesCnt < 10);

	if (callPos == -1)
		return ERROR_INVALID_FILE;

	int branchPos = callPos + 8;
	DWORD NavCallInstruction =  *((DWORD*)(callFnAddrCode + branchPos));
	DWORD NavCallVirtAddr = rtextSection->VirtualAddress + addrPos - callFnDataSize + branchPos - rtextSection->PointerToRawData 
		+ ntHeader.OptionalHeader.ImageBase;
	DWORD NavCallFn = GetBranchAddr(NavCallVirtAddr, NavCallInstruction);

	const int ppCallOffset = 12;
	DWORD ppInstruction = *((DWORD*)(callFnAddrCode + branchPos + ppCallOffset));
	DWORD ppCallVirtAddr  =  NavCallVirtAddr + ppCallOffset;
	DWORD ppCallFn = GetBranchAddr(ppCallVirtAddr, ppInstruction);
	delete [] callFnAddrCode;

	/* --------  print page name  -------- */
	DWORD printPageNameInstr = 0;
	DWORD printPageNameVirtAddr = 0;
	DWORD printPageNameFn = 0;

	int printPageNameFilePos = ppCallFn - rtextSection->VirtualAddress - ntHeader.OptionalHeader.ImageBase + rtextSection->PointerToRawData;
	fseek(f, printPageNameFilePos, SEEK_SET);
	const int maxInstCount = 40;
	DWORD* printPageNameCallFnBlock = new DWORD[maxInstCount];
	fread(printPageNameCallFnBlock, sizeof(DWORD), maxInstCount, f);
	int ebCnt = 0;
	for (int i = 0; i < maxInstCount; i++)
	{
		DWORD instr = (printPageNameCallFnBlock[i] & 0xFF000000) >> 24;
		if (instr == 0xEB | instr == 0x0B) 
		{
			ebCnt++;
			if (ebCnt == 3) // we are looking for 3rd fn.
			{
				printPageNameInstr = printPageNameCallFnBlock[i];
				printPageNameVirtAddr = ppCallFn + i * sizeof(DWORD);
				printPageNameFn = GetBranchAddr(printPageNameVirtAddr, printPageNameInstr);
				break;
			}
		}
	}
	delete [] printPageNameCallFnBlock;

	delete [] sectionHeaders;
	fclose(f);

	if (printPageNameInstr == 0)
		return ERROR_INVALID_FILE;

	settings->NavigateInComplete.FnAddr = NavCallVirtAddr;
	settings->NavigateInComplete.OrgnFnCall = NavCallInstruction;
	settings->NavigateInComplete.OrgnFn = NavCallFn;

	settings->PrintPageName.FnAddr = printPageNameVirtAddr;
	settings->PrintPageName.OrgnFnCall = printPageNameInstr;
	settings->PrintPageName.OrgnFn = printPageNameFn;

	return 1;
}

const LPTSTR LastPatchRelPath = L"\\ManilaTodayPage\\LastPatch.dll";

int GetLastAppliedPatch(MANILA_TODAY_PATCH_SETTINGS* patch)
{
	TCHAR lastPatchPath[MAX_PATH];
	FormatSpecialFolderPath(CSIDL_PROGRAM_FILES, LastPatchRelPath, lastPatchPath);
	FILE* f = _wfopen(lastPatchPath, L"rb");
	if (!f)
		return 0;

	fread(patch, sizeof(MANILA_TODAY_PATCH_SETTINGS), 1, f);
	fclose(f);
	return 1;
}

void SaveLastAppliedPatch(MANILA_TODAY_PATCH_SETTINGS* patch)
{
	TCHAR lastPatchPath[MAX_PATH];
	FormatSpecialFolderPath(CSIDL_PROGRAM_FILES, LastPatchRelPath, lastPatchPath);
	FILE* f = _wfopen(lastPatchPath, L"wb");
	fwrite(patch, sizeof(MANILA_TODAY_PATCH_SETTINGS), 1, f);
	fclose(f);
}

void LoadPatches(list<MANILA_TODAY_PATCH_SETTINGS>* patchList)
{
	MANILA_TODAY_PATCH_SETTINGS s;

	// manil2-Rhodiom.exe
	s.NavigateInComplete.FnAddr = 0x3AFF0;
	s.NavigateInComplete.OrgnFnCall = 0xEBFF8BE7;
	s.NavigateInComplete.OrgnFn = 0x1DF94;

	s.PrintPageName.FnAddr = 0x27FCF0;
	s.PrintPageName.OrgnFnCall = 0xEBF96C8E;
	s.PrintPageName.OrgnFn = 0xDAF30;
	patchList->push_back(s); 

	// manila-Adow.exe
	s.NavigateInComplete.FnAddr = 0x3D6BC;
	s.NavigateInComplete.OrgnFnCall = 0xEBFF70C5;
	s.NavigateInComplete.OrgnFn = 0x199D8;

	s.PrintPageName.FnAddr = 0x1AB1B8;
	s.PrintPageName.OrgnFnCall = 0xEBFC1806;
	s.PrintPageName.OrgnFn = 0xB11D8;
	patchList->push_back(s); 

	// manila-Ameet.exe
	s.NavigateInComplete.FnAddr = 0x3B898;
	s.NavigateInComplete.OrgnFnCall = 0xEBFF8A63;
	s.NavigateInComplete.OrgnFn = 0x1E22C;

	s.PrintPageName.FnAddr = 0x288360;
	s.PrintPageName.OrgnFnCall = 0xEBF96568;
	s.PrintPageName.OrgnFn = 0xE1908;
	patchList->push_back(s); 

	// manila-amitkapoor.exe
	s.NavigateInComplete.FnAddr = 0x3BD68;
	s.NavigateInComplete.OrgnFnCall = 0xEBFF76EB;
	s.NavigateInComplete.OrgnFn = 0x1991C;

	s.PrintPageName.FnAddr = 0x1953E8;
	s.PrintPageName.OrgnFnCall = 0xEB000140;
	s.PrintPageName.OrgnFn = 0x1958F0;
	patchList->push_back(s); 

	// manila-bbonzz.exe
	s.NavigateInComplete.FnAddr = 0x3BF98;
	s.NavigateInComplete.OrgnFnCall = 0xEBFF88CF;
	s.NavigateInComplete.OrgnFn = 0x1E2DC;

	s.PrintPageName.FnAddr = 0x2884B4;
	s.PrintPageName.OrgnFnCall = 0xEBF95FCE;
	s.PrintPageName.OrgnFn = 0xE03F4;
	patchList->push_back(s); 

	// manila-blezalex.exe
	s.NavigateInComplete.FnAddr = 0x3DAD4;
	s.NavigateInComplete.OrgnFnCall = 0xEBFF6FEB;
	s.NavigateInComplete.OrgnFn = 0x19A88;

	s.PrintPageName.FnAddr = 0x1A4600;
	s.PrintPageName.OrgnFnCall = 0xEB00013E;
	s.PrintPageName.OrgnFn = 0x1A4B00;
	patchList->push_back(s); 

	// manila-Carpocalypse .exe
	s.NavigateInComplete.FnAddr = 0x3C804;
	s.NavigateInComplete.OrgnFnCall = 0xEBFF74D0;
	s.NavigateInComplete.OrgnFn = 0x19B4C;

	s.PrintPageName.FnAddr = 0x19D9D4;
	s.PrintPageName.OrgnFnCall = 0xEB00013E;
	s.PrintPageName.OrgnFn = 0x19DED4;
	patchList->push_back(s); 

	// manila-cowboy66.exe
	s.NavigateInComplete.FnAddr = 0x3CFA4;
	s.NavigateInComplete.OrgnFnCall = 0xEBFF71D3;
	s.NavigateInComplete.OrgnFn = 0x196F8;

	s.PrintPageName.FnAddr = 0x1A4EB8;
	s.PrintPageName.OrgnFnCall = 0xEB00013E;
	s.PrintPageName.OrgnFn = 0x1A53B8;
	patchList->push_back(s); 

	// manila-dave.exe
	s.NavigateInComplete.FnAddr = 0x3D96C;
	s.NavigateInComplete.OrgnFnCall = 0xEBFF70C9;
	s.NavigateInComplete.OrgnFn = 0x19C98;

	s.PrintPageName.FnAddr = 0x1A3EC0;
	s.PrintPageName.OrgnFnCall = 0xEB00013B;
	s.PrintPageName.OrgnFn = 0x1A43B4;
	patchList->push_back(s); 

	// manila-heretic.exe
	s.NavigateInComplete.FnAddr = 0x3DB98;
	s.NavigateInComplete.OrgnFnCall = 0xEBFF7256;
	s.NavigateInComplete.OrgnFn = 0x1A4F8;

	s.PrintPageName.FnAddr = 0x1A9204;
	s.PrintPageName.OrgnFnCall = 0xEBFC1FED;
	s.PrintPageName.OrgnFn = 0xB11C0;
	patchList->push_back(s); 

	// manila-Jonfen.exe
	s.NavigateInComplete.FnAddr = 0x3DBBC;
	s.NavigateInComplete.OrgnFnCall = 0xEBFF6F60;
	s.NavigateInComplete.OrgnFn = 0x19944;

	s.PrintPageName.FnAddr = 0x1AA7F8;
	s.PrintPageName.OrgnFnCall = 0xEBFC1E63;
	s.PrintPageName.OrgnFn = 0xB218C;
	patchList->push_back(s); 

	// manila-mrfrank.exe
	s.NavigateInComplete.FnAddr = 0x3D02C;
	s.NavigateInComplete.OrgnFnCall = 0xEBFF7291;
	s.NavigateInComplete.OrgnFn = 0x19A78;

	s.PrintPageName.FnAddr = 0x1A5C58;
	s.PrintPageName.OrgnFnCall = 0xEB000140;
	s.PrintPageName.OrgnFn = 0x1A6160;
	patchList->push_back(s); 

	// manila-str0nz0 .exe
	s.NavigateInComplete.FnAddr = 0x3BDE0;
	s.NavigateInComplete.OrgnFnCall = 0xEBFF8913;
	s.NavigateInComplete.OrgnFn = 0x1E234;

	s.PrintPageName.FnAddr = 0x28A934;
	s.PrintPageName.OrgnFnCall = 0xEBF95D2F;
	s.PrintPageName.OrgnFn = 0xE1DF8;
	patchList->push_back(s); 

	// manila-WallyGator .exe
	s.NavigateInComplete.FnAddr = 0x3F040;
	s.NavigateInComplete.OrgnFnCall = 0xEBFF6AE2;
	s.NavigateInComplete.OrgnFn = 0x19BD0;

	s.PrintPageName.FnAddr = 0x1C3CF8;
	s.PrintPageName.OrgnFnCall = 0xEBFBC858;
	s.PrintPageName.OrgnFn = 0xB5E60;
	patchList->push_back(s);
}